﻿using ETW.EventListeners.ObjectValues;

namespace ETW.EventListeners.Listeners
{
    /// <summary>
    /// Signal连接事件监听器
    /// Microsoft.AspNetCore.Http.Connections
    /// <para>
    /// 该监听器中的计数器作为 ASP.NET Core SignalR 的一部分发布，并在 HttpConnectionsEventSource.cs 中进行维护。
    /// </para>
    /// <para>
    /// https://docs.microsoft.com/zh-cn/dotnet/core/diagnostics/available-counters#microsoftaspnetcorehttpconnections-counters
    /// </para>
    /// </summary>
    public class SignalRConnectionsEventListener:EventListener
    {
        #region 事件
        /// <summary>
        /// 当计数器写入 连接的平均持续时间（毫秒） 时触发
        /// <para>Average Connection Duration (connections-duration)</para>
        /// </summary>
        public event Action<MeanCounterPayload, EventWrittenEventArgs> OnConnectionsDurationWritten;
        /// <summary>
        /// 当计数器写入 已启动但尚未停止的活动连接数 时触发
        /// <para>Current Connections (current-connections)</para>
        /// </summary>
        public event Action<SumCounterPayload, EventWrittenEventArgs> OnCurrentConnectionsWritten;
        /// <summary>
        /// 当计数器写入 已启动的连接总数 时触发
        /// <para>Total Connections Started (connections-started)</para>
        /// </summary>
        public event Action<SumCounterPayload, EventWrittenEventArgs> OnTotalConnectionsStartedWritten;
        /// <summary>
        /// 当计数器写入 已停止的连接总数  时触发
        /// <para>Total Connections Stopped (connections-stopped)</para>
        /// </summary>
        public event Action<SumCounterPayload, EventWrittenEventArgs> OnTotalConnectionsstoppedWritten;
        /// <summary>
        /// 当计数器写入 已超时的连接总数 时触发
        /// <para>Total Connections Timed Out (connections-timed-out)</para>
        /// </summary>
        public event Action<SumCounterPayload, EventWrittenEventArgs> OnTotalConnectionsTimedOutWritten;
        #endregion

        public SignalRConnectionsEventListener() { }

        protected override void OnEventSourceCreated(EventSource eventSource)
        {
            if (!eventSource.Name.Equals("Microsoft.AspNetCore.Http.Connections")) return;

            // 启用时间，并设置事件等级、事件关键字及事件计数器间隔时间(单位秒)
            EnableEvents(eventSource, DefaultConfiguration.SignalRConnectionsEventListenerOptions.EventLevel, DefaultConfiguration.SignalRConnectionsEventListenerOptions.EventKeywords, new Dictionary<string, string> { ["EventCounterIntervalSec"] = DefaultConfiguration.SignalRConnectionsEventListenerOptions.EventCounterIntervalSec.ToString() });
        }

        protected override void OnEventWritten(EventWrittenEventArgs eventData)
        {
            if (!"EventCounters".Equals(eventData.EventName)) return;
            if (!"Microsoft.AspNetCore.Http.Connections".Equals(eventData.EventSource.Name)) return;

            for (var i = 0; i < eventData.Payload.Count; i++)
            {
                if (eventData.Payload[i] is IDictionary<string, object> eventPayload)
                {
                    var counterName = GetName(eventPayload);

                    MeanCounterPayload meanCounterPayload = null;
                    SumCounterPayload sumCounterPayload = null;
                    var CounterType = eventPayload["CounterType"].ToString();

                    if (CounterType.Equals("Mean"))
                        meanCounterPayload = MeanCounterPayload.ConvertFrom(eventPayload);
                    else if (CounterType.Equals("Sum"))
                        sumCounterPayload = SumCounterPayload.ConvertFrom(eventPayload);
                    else continue;

                    switch (counterName)
                    {
                        case "connections-duration":
                            if (OnConnectionsDurationWritten != null)
                                OnConnectionsDurationWritten.Invoke(meanCounterPayload, eventData);
                                //Task.Factory.StartNew(() => OnConnectionsDurationWritten.Invoke(meanCounterPayload, eventData));
                            break;
                        case "current-connections":
                            if (OnCurrentConnectionsWritten != null)
                                OnCurrentConnectionsWritten.Invoke(sumCounterPayload, eventData);
                                //Task.Factory.StartNew(() => OnCurrentConnectionsWritten.Invoke(sumCounterPayload, eventData));
                                break;
                        case "connections-started":
                            if (OnTotalConnectionsStartedWritten != null)
                                OnTotalConnectionsStartedWritten.Invoke(sumCounterPayload, eventData);
                                //Task.Factory.StartNew(() => OnTotalConnectionsStartedWritten.Invoke(sumCounterPayload, eventData));
                            break;
                        case "connections-stopped":
                            if (OnTotalConnectionsStartedWritten != null)
                                OnTotalConnectionsStartedWritten.Invoke(sumCounterPayload, eventData);
                                //Task.Factory.StartNew(() => OnTotalConnectionsStartedWritten.Invoke(sumCounterPayload, eventData));
                            break;
                        case "connections-timed-out":
                            if (OnTotalConnectionsTimedOutWritten != null)
                                OnTotalConnectionsTimedOutWritten.Invoke(sumCounterPayload, eventData);
                                //Task.Factory.StartNew(() => OnTotalConnectionsTimedOutWritten.Invoke(sumCounterPayload, eventData));
                            break;
                    }
                }
            }
        }

        private static string GetName(IDictionary<string, object> eventPayload)
        {
            var counterName = "";
            if (eventPayload.TryGetValue("Name", out object displayValue))
            {
                counterName = displayValue.ToString();
            }

            return counterName;
        }
    }
}
